package Hunters;

import Bots.Bots;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Configuration;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.RemoveRay;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.StopShooting;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.*;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
import cz.cuni.amis.utils.exception.PogamutException;
import cz.cuni.amis.utils.flag.FlagListener;

import javax.vecmath.Vector3d;

@AgentScoped
@Deprecated
public class RaycastingBot extends UT2004BotModuleController {

    private boolean first = true;
    private boolean raysInitialized = false;
    private int turnSleep = 250;


    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    private boolean moving = false;

    protected void goForward() {
        move.moveContinuos();
        moving = true;
    }

    /////////////////////////////////////////////
    public Player enemy;

    protected void stateEngage() {
        double distance = Double.MAX_VALUE;
        if (enemy == null || !enemy.isVisible()) {
            enemy = players.getNearestVisiblePlayer(players.getVisibleEnemies().values());
            if (enemy == null) {
                return;
            }
        }

        if (!enemy.isVisible()) {
            if (info.isShooting() || info.isSecondaryShooting()) {
                getAct().act(new StopShooting());
            }
        } else {
            distance = info.getLocation().getDistance(enemy.getLocation());
            if (shoot.shoot(weaponPrefs, enemy) != null) {
            }
        }

        int decentDistance = Math.round(random.nextFloat() * 800) + 200;
        if (!enemy.isVisible() || decentDistance < distance) {
            navigation.navigate(enemy);
        } else {
            navigation.stopNavigation();
        }

    }


    ///////////////////////////////////////////    
    private boolean sensorLeft45 = false;
    private boolean sensorRight45 = false;
    private boolean sensorFront = false;
    private boolean sensor = false;

    private int smallTurn = 30;
    private int bigTurn = 90;

    @Override
    public void logic() throws PogamutException {
        log.info("--- Logic iteration ---");
        if (!raycasting.getAllRaysInitialized().getFlag()) {
            return;
        }
        sensorFront = front.isResult();
        sensorLeft45 = left.isResult();
        sensorRight45 = right.isResult();
        sensor = sensorFront || sensorLeft45 || sensorRight45;

        if (!sensor) {
            goForward();
            return;
        }
        if (moving) {
            move.stopMovement();
            moving = false;
        }
        if (sensorFront) {
            if (sensorLeft45) {
                if (sensorRight45) {
                    move.turnHorizontal(bigTurn);
                } else {
                    move.turnHorizontal(smallTurn);
                }
            } else {
                if (sensorRight45) {
                    move.turnHorizontal(-smallTurn);
                } else {
                    move.turnHorizontal(smallTurn);
                }
            }
        } else {
            if (sensorLeft45) {
                if (sensorRight45) {
                    goForward();
                } else {
                    move.turnHorizontal(smallTurn);
                }
            } else {
                if (sensorRight45) {
                    move.turnHorizontal(-smallTurn);
                } else {
                    goForward();
                }
            }
        }
        stateEngage();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    private AutoTraceRay left, front, right;

    FlagListener<Boolean> FlagListener = new FlagListener<Boolean>() {
        @Override
        public void flagChanged(Boolean changedValue) {
            left = raycasting.getRay(LEFT45);
            front = raycasting.getRay(FRONT);
            right = raycasting.getRay(RIGHT45);
        }
    };
    //////////////////////////////////////////////////////////////
    private static int instanceCount = 0;

    @Override
    public Initialize getInitializeCommand() {
        return new Initialize().setName("Hunter_RaycastingBot-" + (++instanceCount)).setDesiredSkill(5);
    }

    //////////////////////////////////////////
    protected static final String FRONT = "frontRay";
    protected static final String LEFT45 = "left45Ray";
    protected static final String LEFT90 = "left90Ray";
    protected static final String RIGHT45 = "right45Ray";
    protected static final String RIGHT90 = "right90Ray";

    private float moveSpeed = 0.6f;

    @Override
    public void botInitialized(GameInfo info, ConfigChange currentConfig, InitedMessage init) {

        final int rayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * 10);
        boolean fastTrace = true;
        boolean floorCorrection = false;
        boolean traceActor = false;

        getAct().act(new RemoveRay("All"));

        raycasting.createRay(LEFT45, new Vector3d(1, -1, 0), rayLength, fastTrace, floorCorrection, traceActor);
        raycasting.createRay(FRONT, new Vector3d(1, 0, 0), rayLength, fastTrace, floorCorrection, traceActor);
        raycasting.createRay(RIGHT45, new Vector3d(1, 1, 0), rayLength, fastTrace, floorCorrection, traceActor);
        raycasting.createRay(LEFT90, new Vector3d(0, -1, 0), rayLength, fastTrace, floorCorrection, traceActor);
        raycasting.createRay(RIGHT90, new Vector3d(0, 1, 0), rayLength, fastTrace, floorCorrection, traceActor);

        raycasting.getAllRaysInitialized().addListener(FlagListener);
        raycasting.endRayInitSequence();

        config.setSpeedMultiplier(moveSpeed);
        getAct().act(new Configuration().setDrawTraceLines(true).setAutoTrace(true));
    }

    //////////////////////////////////////////////////
    private static int agent_num = 2;
    public static Bots[] bots;

    static int numState = 28;
    static int numAction = 5;
    static int numReward = 2;

    public static void main(String args[]) throws PogamutException {
        bots = new Bots[agent_num];
        for (int i = 0; i < agent_num; i++) {
            bots[i] = new Bots(i, numState, numAction);
        }
        new UT2004BotRunner(RaycastingBot.class, "RaycastingBot").setMain(true).startAgents(agent_num);
    }
}
